﻿using AutoMapper;
using ProjectManageSystemApi.DbEntity;
using ProjectManageSystemApi.Models;
using ProjectManageSystemApi.Utilities;
using System;
using System.Collections.Generic;

namespace ProjectManageSystemApi.Services
{
    public class CostApplyService : ICostApplyService
    {
        readonly IFreeSql _fsql;
        readonly IMapper _mapper;
        readonly ICostApplyImageServices _imageService;
        public CostApplyService(IFreeSql fsql, IMapper mapper, ICostApplyImageServices imageService)
        {
            _fsql = fsql;
            _mapper = mapper;
            _imageService = imageService;
        }

        /// <summary>
        /// 增加报销接口
        /// </summary>
        public bool Create(CostApplyDto costInfo)
        {
            try
            {
                _fsql.Transaction(() =>
                {
                    var data = _mapper.Map<CostInfo>(costInfo);
                    data.CreateTime = DateTime.Now;
                    data.State = (sbyte)EnumCostApplyInfo.Nomal;
                    data.ManagerApproveUser = null;
                    data.ManagerApproveTime = null;
                    data.ManagerApproveReason = null;
                    data.FinancerApproveUser = null;
                    data.FinancerApproveTime = null;
                    data.FinancerApproveReason = null;
                    int costId = (int)_fsql.Insert(data).ExecuteIdentity();
                    if (costId <= 0)
                    {
                        throw new DbTranException("保存报销数据失败");
                    }
                    if (costInfo.Images.Count <= 0)
                    {
                        return;
                    }
                    if (!_imageService.Insert(costId, costInfo.Images, costInfo.CreateUserId))
                    {
                        throw new DbTranException("保存报销图片失败");
                    }
                });
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// 修改报销信息接口，对于没有审核的报销均可以修改
        /// </summary>
        /// <param name="costInfo"></param>
        /// <returns></returns>
        public bool Update(CostApplyDto costInfo)
        {
            try
            {
                _fsql.Transaction(() =>
                {
                    var data = _mapper.Map<CostInfo>(costInfo);
                    int r = _fsql.Update<CostInfo>(data.Id).SetSource(data)
                        .IgnoreColumns(i => new { i.CreateUser, i.CreateTime, i.FinancerApproveReason, i.FinancerApproveTime, i.FinancerApproveUser, i.ProjectId, i.State })
                        .ExecuteAffrows();
                    if (r <= 0)
                    {
                        throw new DbTranException("修改报销数据失败");
                    }
                });
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// 财务查询报销单，有同意，拒绝，未审批
        /// </summary>
        public Models.PageVo<IEnumerable<CostApplyDto>> GetAllByFinancer(Models.PageBo<CostApplyParams> pageBo)
        {
            var datas = _fsql.Select<CostInfo>()
                .Include(x => x.UserInfo)
                .Include(x => x.CostType)
                .Include(x => x.FinancerApproveUserInfo)
                .Include(x => x.ManagerApproveUserInfo)
                .IncludeMany(x => x.Images)
                .Where(d => d.ProjectId == pageBo.Param.ProjectId && d.ItemId == pageBo.Param.ItemId);
            if (pageBo.Param.State == 0)
            {
                datas = datas.Where(d => d.State == (sbyte)EnumCostApplyInfo.ManagerPassed);
            }
            else if (pageBo.Param.State == 1)
            {
                datas = datas.Where(d => d.State == (sbyte)EnumCostApplyInfo.FinancerPassed);
            }
            else if (pageBo.Param.State == 2)
            {
                datas = datas.Where(d => d.State == (sbyte)EnumCostApplyInfo.FinancerUnPassed);
            }
            else
            {
                datas = datas.Where(d => d.State == (sbyte)EnumCostApplyInfo.ManagerPassed || d.State == (sbyte)EnumCostApplyInfo.FinancerPassed || d.State == (sbyte)EnumCostApplyInfo.FinancerUnPassed);
            }
            var total = datas.Count();

            datas = datas.OrderBy(x => x.State);
            datas = datas.Page(pageBo.Page, pageBo.Size);

            var data = new Models.PageVo<IEnumerable<CostApplyDto>>
            {
                Page = pageBo.Page,
                Size = pageBo.Size,
                Datas = _mapper.Map<List<CostApplyDto>>(datas.ToList()),
                Total = total
            };
            return data;
        }

        /// <summary>
        /// 经理查询报销单，有同意，拒绝，未审批
        /// </summary>
        public Models.PageVo<IEnumerable<CostApplyDto>> GetAllByManager(Models.PageBo<CostApplyParams> pageBo)
        {
            var datas = _fsql.Select<CostInfo>()
                .Include(x => x.UserInfo)
                .Include(x => x.CostType)
                .Include(x => x.FinancerApproveUserInfo)
                .Include(x => x.ManagerApproveUserInfo)
                .IncludeMany(x => x.Images)
                .Where(d => d.ProjectId == pageBo.Param.ProjectId && d.ItemId == pageBo.Param.ItemId);
            if (pageBo.Param.State == 0)
            {
                datas = datas.Where(d => d.State == (sbyte)EnumCostApplyInfo.Nomal);
            }
            else if (pageBo.Param.State == 1)
            {
                datas = datas.Where(d => d.State == (sbyte)EnumCostApplyInfo.ManagerPassed 
                    || d.State == (sbyte)EnumCostApplyInfo.FinancerPassed
                    || d.State == (sbyte)EnumCostApplyInfo.FinancerUnPassed);
            }
            else if (pageBo.Param.State == 2)
            {
                datas = datas.Where(d => d.State == (sbyte)EnumCostApplyInfo.ManagerUnPassed);
            }
            else
            {
                datas = datas.Where(d => d.State < (sbyte)EnumCostApplyInfo.Delete);
            }
            var total = datas.Count();

            datas = datas.OrderBy(x => x.State).OrderByDescending(x => x.CreateTime);
            datas = datas.Page(pageBo.Page, pageBo.Size);

            var data = new Models.PageVo<IEnumerable<CostApplyDto>>
            {
                Page = pageBo.Page,
                Size = pageBo.Size,
                Datas = _mapper.Map<List<CostApplyDto>>(datas.ToList()),
                Total = total
            };
            return data;
        }

        /// <summary>
        /// 查询所有发票
        /// </summary>
        /// <param name="pageBo"></param>
        /// <returns></returns>
        public Models.PageVo<IEnumerable<CostApplyDto>> GetAll(Models.PageBo<CostApplyParams> pageBo)
        {
            var datas = _fsql.Select<CostInfo>()
                .Include(x => x.UserInfo)
                .Include(x => x.CostType)
                .Include(x => x.FinancerApproveUserInfo)
                .Include(x => x.ManagerApproveUserInfo)
                .IncludeMany(x => x.Images)
                .Where(d => d.ProjectId == pageBo.Param.ProjectId && d.ItemId == pageBo.Param.ItemId);
            if (pageBo.Param.State == -1)
            {
                datas = datas.Where(d => d.State < (int)EnumCostApplyInfo.Delete);
            }
            else
            {
                datas = datas.Where(d => d.State == pageBo.Param.State);
            }

            var total = datas.Count();

            datas = datas.OrderBy(x => x.State);
            datas = datas.Page(pageBo.Page, pageBo.Size);

            var data = new Models.PageVo<IEnumerable<CostApplyDto>>
            {
                Page = pageBo.Page,
                Size = pageBo.Size,
                Datas = _mapper.Map<List<CostApplyDto>>(datas.ToList()),
                Total = total
            };
            return data;
        }

        /// <summary>
        /// 手机端，获取我提交的报销单
        /// </summary>
        public Models.PageVo<IEnumerable<CostApplyDto>> GetMyCostApplyList(Models.PageBo<GetMyCostApplyListBo> pageBo)
        {
            var datas = _fsql.Select<CostInfo>().Where(p => p.State < (int)EnumCostApplyInfo.Delete)
                .Include(x => x.ProjectInfo)
                .Include(x => x.ProjectItemInfo)
                .Include(x => x.CostType)
                .Include(x => x.ManagerApproveUserInfo)
                .Include(x => x.FinancerApproveUserInfo)
                .IncludeMany(x => x.Images)
                .Where(x => x.UserId == pageBo.Param.UserId)
                .OrderByDescending(x => x.CreateTime);
            if (pageBo.Param.ProjectId > 0)
            {
                datas = datas.Where(d => d.ProjectId == pageBo.Param.ProjectId);
            }
            if (pageBo.Param.State != -1)
            {
                datas = datas.Where(d => d.State == pageBo.Param.State);
            }
            var total = datas.Count();
            datas = datas.Page(pageBo.Page, pageBo.Size);

            var data = new Models.PageVo<IEnumerable<CostApplyDto>>
            {
                Page = pageBo.Page,
                Size = pageBo.Size,
                Datas = _mapper.Map<List<CostApplyDto>>(datas.ToList()),
                Total = total
            };
            return data;
        }

        public bool UpdateState(int costId, EnumCostApplyInfo state)
        {
            return _fsql.Update<CostInfo>().Set(x => x.State, (int)state).Where(x => x.Id == costId).ExecuteAffrows() > 0;
        }
        public bool ManagerCostCheck(CostCheckData costCheck, long userId)
        {
            return _fsql.Update<CostInfo>(costCheck.Id)
                .Set(x => x.State, costCheck.State == 1
                    ? (sbyte)EnumCostApplyInfo.ManagerPassed
                    : (sbyte)EnumCostApplyInfo.ManagerUnPassed)
                .Set(x => x.ManagerApproveReason, costCheck.Reason)
                .Set(x => x.ManagerApproveUser, userId)
                .Set(x => x.ManagerApproveTime, DateTime.Now)
                .ExecuteAffrows() > 0;
        }

        public bool FinancerCostCheck(CostCheckData costCheck, long userId) 
        {
            return _fsql.Update<CostInfo>(costCheck.Id)
                .Set(x => x.State, costCheck.State == 1 
                    ? (sbyte)EnumCostApplyInfo.FinancerPassed 
                    : (sbyte)EnumCostApplyInfo.FinancerUnPassed)
                .Set(x => x.FinancerApproveReason, costCheck.Reason)
                .Set(x => x.FinancerApproveUser, userId)
                .Set(x=>x.FinancerApproveTime, DateTime.Now)
                .ExecuteAffrows() > 0;
        }

        public CostApplyDto GetCostInfoById(int id)
        {
            var data = _fsql.Select<CostInfo>()
                .Include(x => x.UserInfo)
                .Include(x => x.FinancerApproveUserInfo)
                .Include(x => x.ManagerApproveUserInfo)
                .Include(x=> x.ProjectInfo)
                .Include(x=> x.ProjectItemInfo)
                .Include(x => x.CostType)
                .IncludeMany(x => x.Images)
                .Where(d => d.Id == id).ToOne();

            if (data == null) 
            {
                return null;
            }
            return _mapper.Map<CostApplyDto>(data);
        }



        /// <summary>
        /// 判断是否存在该报销名称
        /// </summary>
        public bool HasExistCostName(int projectId, string costName, int id)
        {
            return _fsql.Select<CostInfo>().Any(p => p.Id != id && p.ProjectId == projectId && p.CostName == costName && p.State < (int)EnumCostApplyInfo.Delete);
        }

        public bool HasExistById(int costId)
        {
            return _fsql.Select<CostInfo>().Any(p => p.Id == costId && p.State < (int)EnumCostApplyInfo.Delete);
        }

        /// <summary>
        ///  是否允许修改，已经审批过的不允许修改
        /// </summary>
        /// <param name="costId"></param>
        /// <returns></returns>
        public bool HasAllowUpdate(int costId) 
        {
            return _fsql.Select<CostInfo>().Any(p => p.Id == costId && p.State == (int)EnumCostApplyInfo.Nomal);
        }

        /// <summary>
        /// 判断是否为经理审核状态
        /// </summary>
        public bool HasStatus(int costId, EnumCostApplyInfo status)
        {
            return _fsql.Select<CostInfo>().Any(p => p.Id == costId && p.State == (sbyte)status);
        }
    }
}
